package com.bkgy.config;

import com.bkgy.modular.test.exception.SystemExceptionNew;
import com.bkgy.sys.common.entity.ResultData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DataAccessException;
import org.springframework.validation.BindException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingPathVariableException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolationException;
import java.sql.SQLIntegrityConstraintViolationException;
import java.util.stream.Collectors;

/**
 * 全局异常处理器
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 请求方式不支持
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public ResultData handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e, HttpServletRequest request) {
        String requestURI = request.getRequestURI();
        log.error("请求地址'{}',不支持'{}'请求", requestURI, e.getMethod());
        return ResultData.ResultDataFaultSelf("请求方式不支持", null);
    }

    /**
     * 请求路径中缺少必需的路径变量
     */
    @ExceptionHandler(MissingPathVariableException.class)
    public ResultData handleMissingPathVariableException(MissingPathVariableException e, HttpServletRequest request) {
        String requestURI = request.getRequestURI();
        log.error("请求路径中缺少必需的路径变量'{}',发生系统异常{}", requestURI, e);
        return ResultData.ResultDataFaultSelf(String.format("请求路径中缺少必需的路径变量[%s]", e.getVariableName()), null);
    }

    /**
     * 请求参数类型不匹配
     */
    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    public ResultData handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e, HttpServletRequest request) {
        String requestURI = request.getRequestURI();
        log.error("请求参数类型不匹配'{}',发生系统异常{}", requestURI, e);
        return ResultData.ResultDataFaultSelf(
                String.format("请求参数类型不匹配，参数[%s]要求类型为：'%s'", e.getName(), e.getRequiredType().getName()),
                null);
    }

    /**
     * 参数绑定异常
     */
    @ExceptionHandler(BindException.class)
    public ResultData handleBindException(BindException e) {
        log.error("参数绑定异常", e);
        String message = e.getAllErrors().get(0).getDefaultMessage();
        return ResultData.ResultDataFaultSelf(message, null);
    }

    /**
     * 参数校验异常
     */
    /**
     * 参数校验异常（RequestBody）
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResultData handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        log.error("参数校验异常", e);
        String message = e.getBindingResult().getFieldErrors().stream()
                .map(fieldError -> fieldError.getField() + ": " + fieldError.getDefaultMessage())
                .collect(Collectors.joining("; "));
        return ResultData.ResultDataFaultSelf(message, null);
    }

    /**
     * 参数校验异常（路径/Query参数）
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public ResultData handleConstraintViolationException(ConstraintViolationException e, HttpServletRequest request) {
        String requestURI = request.getRequestURI();
        log.error("请求地址'{}'参数校验失败: {}", requestURI, e.getMessage());
        String message = e.getConstraintViolations().stream()
                .map(violation -> violation.getPropertyPath() + ": " + violation.getMessage())
                .collect(Collectors.joining("; "));
        return ResultData.ResultDataFaultSelf(message, null);
    }

    /**
     * 业务异常
     */
    @ExceptionHandler(BusinessException.class)
    public ResultData handleBusinessException(BusinessException e, HttpServletRequest request) {
        String requestURI = request.getRequestURI();
        log.error("请求地址'{}',发生业务异常{}", requestURI, e);
        return ResultData.ResultDataFaultSelf(e.getMessage(), null);
    }

    /**
     * SQL执行异常，例如：违反唯一性等
     */
    @ExceptionHandler(value = DataAccessException.class)
    public ResultData sqlException(SQLIntegrityConstraintViolationException e) {
        return ResultData.ResultDataFaultSelf("数据违反了完整性约束。请检查输入数据。", null);
    }

    /**
     * 系统异常
     */
    @ExceptionHandler(SystemExceptionNew.class)
    public ResultData handleSystemException(SystemExceptionNew e, HttpServletRequest request) {
        String requestURI = request.getRequestURI();
        log.error("请求地址'{}',系统异常{}", requestURI, e);
        return ResultData.ResultDataFaultSelf(e.getMessage(), null);
    }

    /**
     * 拦截未知的运行时异常
     */
    @ExceptionHandler(RuntimeException.class)
    public ResultData handleRuntimeException(RuntimeException e, HttpServletRequest request) {
        String requestURI = request.getRequestURI();
        log.error("请求地址'{}',发生未知异常{}", requestURI, e);
        return ResultData.ResultDataFaultSelf("系统运行时异常", null);
    }

    /**
     * 系统异常
     */
    @ExceptionHandler(Exception.class)
    public ResultData handleException(Exception e, HttpServletRequest request) {
        String requestURI = request.getRequestURI();
        log.error("请求地址'{}',发生系统异常{}", requestURI, e);
        return ResultData.ResultDataFaultSelf("系统异常", null);
    }
}